import { CanvasKeyBoardEvent, CanvasMouseEvent } from "./Event";
import { Vec2 } from "./Math2d";
import { Timer, TimerCallback } from "./Timer";

abstract class Application implements EventListenerObject {
    protected _start = false;
    protected _requestId = -1;
    protected _lastTime = -1;
    protected _startTIme = 0;

    canvas: HTMLCanvasElement;
    _isMouseDown: boolean;
    isSupportMouseMove: boolean;

    timers:Timer[] = [];
    private _timeId = -1;

    constructor(canvas: HTMLCanvasElement) {
        this.canvas = canvas;

        // 鼠标事件
        this.canvas.addEventListener("mousedown", this, false)
        this.canvas.addEventListener("mouseup", this, false)
        this.canvas.addEventListener("mousemove", this, false)

        window.addEventListener("keydown", this, false)
        window.addEventListener("keyup", this, false)
        window.addEventListener("keypress", this, false)

        this._isMouseDown = false;
        this.isSupportMouseMove = false;
    }
    handleEvent(evt: Event): void {
        switch (evt.type) {
            case "mousedown":
                this._isMouseDown = true;
                this.dispatchMouseDown(
                    this._toCanvasMouseEvent(evt)
                )
                break;
            case "mouseup":
                this._isMouseDown = false;
                this.dispatchMouseUp(
                    this._toCanvasMouseEvent(evt)
                )
                break;
            case "mousemove":
                let e = this._toCanvasMouseEvent(evt)
                this.dispatchMouseMove(e)
                //
                if(this._isMouseDown){
                    this.dispatchMouseMove(e)
                }
                break;

            case "keypress":
                this.dispatchKeypress(
                    this._toCanvasKeyboardEvent(evt)
                )
                break;
            case "keyup":
                this.dispatchKeyup(
                    this._toCanvasKeyboardEvent(evt)
                )
                break;
            case "keydown":
                this.dispatchKeydown(
                    this._toCanvasKeyboardEvent(evt)
                )
                break;

        }
    }
    _toCanvasMouseEvent(evt: Event): CanvasMouseEvent {
        let event = evt as MouseEvent;
        let mousePosition = this._viewportToCanvasCoordinate(event);
        // console.log("evt",mousePosition)
        return new CanvasMouseEvent(
            mousePosition,
            event.button,
            event.altKey,
            event.ctrlKey,
            event.shiftKey
        )
    }
    _toCanvasKeyboardEvent(evt: Event): CanvasKeyBoardEvent {
        let event = evt as KeyboardEvent;
        return new CanvasKeyBoardEvent(
            event.key,
            event.keyCode,
            event.repeat,
            event.altKey,
            event.ctrlKey,
            event.shiftKey
        )
    }
    _viewportToCanvasCoordinate(evt:MouseEvent):Vec2{
        // getBoundingClientRect()
        if(this.canvas){
            let rect = this.canvas.getBoundingClientRect();
            if(evt.type == "mousedown"){
                console.log("rect",JSON.stringify(rect))
                console.log("viewport",`${evt.clientX},${evt.clientY}`)
            }
            let x = evt.clientX - rect.left;
            let y = evt.clientY - rect.top;
            return Vec2.create(x,y);
        }else{
            alert("canvas未初始化")
        }
        return Vec2.create()
    }
    // 事件回调函数
    protected dispatchMouseDown(evt:CanvasMouseEvent){}
    protected dispatchMouseUp(evt:CanvasMouseEvent){}
    protected dispatchMouseMove(evt:CanvasMouseEvent){}
    protected dispatchMouseDrag(evt:CanvasMouseEvent){}

    protected dispatchKeypress(evt:CanvasKeyBoardEvent){}
    protected dispatchKeydown(evt:CanvasKeyBoardEvent){}
    protected dispatchKeyup(evt:CanvasKeyBoardEvent){}

    start() {
        if (!this._start) {
            this._start = true
            this._requestId = -1
            this._lastTime = -1
            this._startTIme = -1

            this._requestId = requestAnimationFrame(
                (t) => {
                    this.step(t);
                }
            )

        }
    }
    stop() {
        if (this._start) {
            cancelAnimationFrame(this._requestId);

            this._requestId = -1
            this._lastTime = -1
            this._startTIme = -1

            this._start = false
        }
    }
    step(timestamp: number) {
        if (this._startTIme == -1) {
            this._startTIme = timestamp
        }
        // 时间记录
        let elapsedMsec = timestamp - this._startTIme;
        let intervalSec = (timestamp - this._lastTime) / 1000;

        // console.log("app",elapsedMsec,intervalSec) 
        this._handleTimer(intervalSec);
        this.update(elapsedMsec,intervalSec);
        this.render();

        this._lastTime = timestamp;
        requestAnimationFrame(
            (t) => {
                this.step(t);
            }
        )
    }
    isRunnint() {
        return this._start;
    }

    addTimer(
        callback:TimerCallback,
        timerout = 1.0,
        onlyOnece = false,
        data:any = undefined
    ):number{
        let timer : Timer;
        for (let i = 0; i < this.timers.length; i++) {
            let timer  = this.timers[i];
            if(timer.enabled == false){
                timer.callback = callback;
                timer.callbackData = data;
                timer.timeout = timerout
                timer.countdown = timerout
                timer.onlyOnce = onlyOnece;
                timer.enabled = true;
                return timer.id
            }
        }

        this._timeId = this._timeId + 1;
        timer = new Timer(callback);
        timer.id = this._timeId;

        timer.callbackData = data;
        timer.timeout = timerout
        timer.countdown = timerout
        timer.onlyOnce = onlyOnece;
        timer.enabled = true;

        this.timers.push(timer);
        return  timer.id
    }

    removeTimer(id:number):boolean{
        let found = false;

        for (let i = 0; i < this.timers.length; i++) {
            let timer  = this.timers[i];
            if(timer.id === id){
                timer.enabled = false;
                found = true;
                break;
            }
        }

        return false;
    }

    _handleTimer(intervalSec:number):void{
        for (let i = 0; i < this.timers.length; i++) {
            let timer  = this.timers[i];
            //判定enabled
            if(timer.enabled === false){
                continue;
            }
            //计算倒计时
            timer.countdown = timer.countdown - intervalSec;
            if(timer.countdown < 0.0){
                timer.callback(timer.id,timer.callbackData)
                //判定是否只执行一次
                if(timer.onlyOnce == false){
                    timer.countdown = timer.timeout;
                }else{
                    this.removeTimer(timer.id)
                }
            }
        }
    }

    abstract update(elapsedMsec: number, intervalSec: number): void
    abstract render(): void
}

class Canvas2DApplication extends Application {
    context2D:CanvasRenderingContext2D | null;
    constructor(
        canvas:HTMLCanvasElement,
        settings?:CanvasRenderingContext2DSettings
    ){
        super(canvas);
        this.context2D = this.canvas.getContext("2d",settings)
    }
    update(elapsedMsec: number, intervalSec: number): void {
    }
    render(): void {
    }

}

export {
    Application,
    Canvas2DApplication
}